#ifndef _Connection_Pool_
#define _Connection_Pool_

#include <queue>
#include <fstream>
#include <iostream>
#include <memory>
#include <thread>
#include <condition_variable>
#include <jsoncpp/json/json.h>

template <class T>
struct default_deleter;

/* 连接池定义 */
template <class T, class Deleter = default_deleter<T>>
class Connection_Pool
{
    /* 声明为友元, 允许内部调用 recycle 私有方法 */
    friend Deleter;

public:
    /* 获得连接池的全局唯一实例 */
    static Connection_Pool<T, Deleter>* globalInstance();

    /* 从连接池中获取一个连接 */
    std::unique_ptr<T, Deleter> getConnection();

private:
    /* 回收一个连接(仅由Deleter调用) */
    void recycle(T* conn);

private:
    Connection_Pool();
    ~Connection_Pool();
    Connection_Pool(const Connection_Pool& r) = delete;
    Connection_Pool& operator=(const Connection_Pool&) = delete;

private:
    std::queue<T*> conn_que;                /* 存放连接的队列 */
    std::mutex que_mutex;                    /* 队列互斥量 */
    std::condition_variable que_cond;       /* 队列条件变量 */
    int init_conn_nums;                     /* 初始连接数 */
};


/* 以下是模板的具体实现 */ 

template <class T, class Deleter>
Connection_Pool<T, Deleter>* Connection_Pool<T, Deleter>::globalInstance()
{
    static Connection_Pool<T, Deleter> pool;
    return &pool;
}

/* 默认连接删除器(对连接进行回收) */
template <class T>
struct default_deleter {
    void operator() (T* conn) {
        Connection_Pool<T>::globalInstance()->recycle(conn);
    }
};

template <class T, class Deleter>
Connection_Pool<T, Deleter>::Connection_Pool()
{
    Json::Reader reader;
    Json::Value root;
    std::fstream in("../setting.json");

    if (!in.is_open())
    {
        std::cout << "error to open file" << std::endl;
        return;
    }

    /* 解析Json配置文件 */
    if (reader.parse(in, root))
    {
        init_conn_nums = root["conn_pool"]["conn_nums"].asInt();
    }

    in.close();

    for (int i = 0; i < init_conn_nums; i++)
    {
        conn_que.push(new T());
    }
}

template <class T, class Deleter>
Connection_Pool<T, Deleter>::~Connection_Pool()
{
    while (!conn_que.empty())
    {
        T* ptr = conn_que.front();
        conn_que.pop();
        delete ptr;
    }
}

template <class T, class Deleter>
std::unique_ptr<T, Deleter> Connection_Pool<T, Deleter>::getConnection()
{
    std::unique_lock<std::mutex> lk(que_mutex);
    que_cond.wait(lk, [this]{ return !conn_que.empty(); });
    /* 持有互斥锁 */    
    T* ptr = conn_que.front();
    conn_que.pop();
    std::unique_ptr<T, Deleter> sp = std::unique_ptr<T, Deleter>(ptr, Deleter());
    /* 释放互斥锁并通知其它阻塞线程 */
    lk.unlock();
    que_cond.notify_one();
    return sp;
}

template <class T, class Deleter>
void Connection_Pool<T, Deleter>::recycle(T* conn)
{
    /* 严格基于作用域的互斥体 */
    std::lock_guard<std::mutex> lk(que_mutex);
    conn_que.push(conn);
    que_cond.notify_one();
}

#endif // !_Connection_Pool_
